#include "surfacemanager.h"
#include "resourcemanager.h"
#include "file.h"

#include <sstream>
#include <iostream>

SurfaceManager* SurfaceManager::m_self = 0;
string SurfaceManager::m_imageSuffix = ".png";

SurfaceManager::SurfaceManager()
{
	m_self=this;
}

SurfaceManager::~SurfaceManager()
{
	m_self=0;
}

SurfaceManager& SurfaceManager::self()
{
    if(m_self == 0)
        m_self = new SurfaceManager();
    
    return *m_self;
}

bool SurfaceManager::exists()
{
	return m_self!=0;
}


bool SurfaceManager::init()
{
	return true;
}

void SurfaceManager::update()
{
}

void SurfaceManager::shutdown()
{
    map<string, Surface*>::iterator it = m_surfaces.begin();

    for(; it != m_surfaces.end(); ++it)
    {
        delete it->second;
        m_surfaces.erase(it);
    }
}

int SurfaceManager::loadSurface(const string& name, const FlipOption& flipped)
{
    string base_name(name);

    Surface *surface;
    if(!hasSurface(name))
    {
        string imagesDir = ResourceManager::self()["images"];
        
        // Load from flipped
        string::size_type pos = base_name.rfind("-right");
        
        if(pos < string::npos)
        {
            string left_name;
            left_name=base_name.replace(pos, string("-right").size(), "-left");
            return loadSurface(left_name, HorizontalFlip);
        }
        else
        {
            string::size_type pos = base_name.rfind("-down");
            if(pos < string::npos)
            {
                string down_name;
                down_name=base_name.replace(pos, string("-down").size(), "-up");
                return loadSurface(down_name, VerticalFlip);
            }
            
            if(!File::exists(imagesDir + base_name + m_imageSuffix))
                return -1;
        }

        m_surfaces[name] = surface = new Surface(imagesDir + base_name + m_imageSuffix);
        
    }
    
    if(flipped == HorizontalFlip)
    {
        string::size_type pos = base_name.rfind("-left");
        // If there is a "-right" in the name we load the left image
        if(pos < string::npos)
        {
            string right_name=name;
            right_name.replace(pos, string("-left").size(), "-right");
            if(!hasSurface(right_name))
            {
                m_surfaces[right_name] = m_surfaces[name]->getHorizontalFlip();
            }
        }
        else
            return -1;
    }
    else if(flipped == VerticalFlip)
    {
        string::size_type pos = base_name.rfind("-up");
        // If there is a "-down" in the name we load the up image
        if(pos < string::npos)
        {
            string down_name=name;
            down_name.replace(pos, string("-up").size(), "-down");
            if(!hasSurface(down_name))
            {
                m_surfaces[down_name] = m_surfaces[name]->getVerticalFlip();
            }
        }
        else
            return -1;
    }
    
    return 0;
}

int SurfaceManager::loadSpriteSurfaces(const string& name)
{
    string base_name(name);
    FlipOption flipped = NoFlip;
    
    // If exist the name with -0, so it is a sprite with more than one image
    if(File::exists(ResourceManager::self()["images"]+base_name+"-"+"0"+m_imageSuffix))
        ;
    // If exist the only with the name, we load it
    else if(File::exists(ResourceManager::self()["images"]+base_name+m_imageSuffix))
    {
        loadSurface(base_name);
        return 1;
    }
    // If doesn't exist
    else
    {
        string::size_type pos = base_name.rfind("-right");
        // If there is a "-right" in the name we load the left image
        if(pos < string::npos)
        {
            base_name=base_name.replace(pos, string("-right").length(), "-left");

            // If exist the file with the new name
            if(File::exists(ResourceManager::self()["images"]+base_name+"-"+"0"+m_imageSuffix))
            {
                flipped = HorizontalFlip;
            }
            else if(File::exists(ResourceManager::self()["images"]+base_name+m_imageSuffix))
            {
                loadSurface(base_name, HorizontalFlip);
                return 1;
            }
            else
            {
                return -1;
            }
        }
        else
        {
            string::size_type pos = base_name.rfind("-down");
            
            if(pos < string::npos)
            {
                base_name.replace(pos, string("-down").size(), "-up");
                
                if(File::exists(ResourceManager::self()["images"]+base_name+"-"+"0"+m_imageSuffix))
                {
                    flipped = VerticalFlip;
                }
                else if(File::exists(ResourceManager::self()["images"]+name+m_imageSuffix))
                {
                    loadSurface(base_name, VerticalFlip);
                    return 1;
                }
                else
                    return -1;
            }
            else
            {
                return -1;
            }
        }
    }
    
    base_name = base_name+"-";
    int i = 0;
    bool end = false;
    while(!end)
    {
        stringstream iss;
        iss << base_name << i;
        if(loadSurface(iss.str(), flipped) < 0)
            end = true;
        else
            i++;
    }
    return i;
}

bool SurfaceManager::hasSurface(const string& name)
{
    map<string, Surface*>::iterator it =  m_surfaces.find(name);
    return it != m_surfaces.end();
}

Surface* SurfaceManager::getSurface(const string& name)
{
    map<string, Surface*>::iterator it =  m_surfaces.find(name);
    if(it == m_surfaces.end())
        return 0;
    else
        return it->second;
}

void SurfaceManager::removeSurface(const string& name, const FlipOption& flipped)
{
    map<string, Surface*>::iterator it =  m_surfaces.find(name);
    if(it != m_surfaces.end())
    {
        delete it->second;
        m_surfaces.erase(it);
    }
    if(flipped == VerticalFlip)
    {
        string::size_type pos = name.rfind("-left");
        if(pos != name.length() - 5)
            return;
        
        string rightName = name.substr(0, pos - 5) + "-right";
        removeSurface(rightName, NoFlip);
    }
    else if(flipped == HorizontalFlip)
    {
        string::size_type pos = name.rfind("-up");
        if(pos != name.length() - 3)
            return;
        
        string downName = name.substr(0, pos - 3) + "-down";
        removeSurface(downName, NoFlip);
    }
}

void SurfaceManager::removeSpriteSurfaces(const string& name, const FlipOption& flipped)
{
    
    string base_name(name);
    string suffix("");
    
    string::size_type pos = name.find_last_of('-');
    
    if(pos < name.length())
    {
        base_name = name.substr(0, pos);
        suffix = name.substr(pos);
    }
    
    int i = 0;
    while(true)
    {
        stringstream iss;
        iss << base_name << i << suffix;
        
        map<string, Surface*>::iterator it =  m_surfaces.find(name);
        if(it == m_surfaces.end())
            return;
        
        removeSurface(iss.str(), flipped);
        i++;
    }
}

Surface* SurfaceManager::operator[](const string& name)
{
    return getSurface(name);
}
